(ns studyclojure)

(print "hello world")

(+ 8 1)

(- 10000000000000000 9999999999999999999999999)

;; 1. 数据类型
(type 1)

(type 2.2)

(type  "11")

(type :abc)

(type (keyword "b"))

(type (list 1 2))

(type (vector 2 4 6 9))

(type {:a 2 :b 2})

(type (vector 1 2 3 4))

(type #{"sdsd","sdada"})

(type 'a)

(def a 1)

(type #'a)

(if nil 1 2)

;;2. 控制流程

(def a "hello")

(let [a "hello"]
  a)

(if (empty? a)
  :empty
  (do
    (prn "not empty")
    :not-empty))

(when-not (empty? a)
  (prn "not empty")
  (prn "sdadad")
  :hahahhaha)

(case a
  "hello" :hi
  "world" :lala
  :not-match)

(cond (= a "hello啊") :lala
      (= a "world") :baba
      :else :啥也没有)




;; function
;; 函数定义
;;((fn [] "hello world"))
;;(def Example (fn [] "hello world"))
(defn Example [] "hello world")

;;函数调用
(Example)

;; 匿名函数
(#(str "hello " %1) "Tom")

;; 增加doc
(defn hello1
  "哈喽函数"
  [] "say hello")

(hello1)

;; 多参数函数==java中方法重构
(defn hala
  ([] "hello world")
  ([name] str "hello" name))

(hala)

(hala "tom")


;;3、循环、递归
(def vara "hello")
(while (empty? vara)
  (do
    (print "hello world")
    (= vara nil)))


(defn looptest []
  (loop [x 10]
    (when (> x 1)
      (println x)
      (recur (- x 2)))))
(looptest)


(defn sum
  ([vals] (sum 0 vals))
  ([total vals]
   (if (empty? vals)
     total
     (recur (+ total (first vals))
            (reset vals)))))
			
;; 4、高阶函数 map reduce filter
(reduce (fn add [total val]
          (+ total val))  [1 2 3 4])

(map (fn cheng [val]
       + val val) [1 2 3 4])
	   
;; 5、leiningen

;; 6、java交互
;; 6.1 引用java包\java.lang下不需要
;; 6.2 声明（实例化）对象
;; 6.3 方法调用
;; 6.4 clojure中构造java集合
;; 6.5 doto、类型提示
;; 6.6 继承类与实现接口
;; 6.7 gen-class（动态生成类）和aot（预先编译）
;; 6.8 项目中Clojure和Java混合开发

;; 6.1、导入包
  (:import [java.util Date])
  (:import [java.beans Beans]))

;; 6.2、实例化对象
;;(import java.util.Date)
(new Date)

(Date.)

(Date. (System/currentTimeMillis))

;; (import java.beans.Beans)
(Beans.)

(System/currentTimeMillis)

;; 6.3、方法调用
(. (Date.) getTime)

(.getTime (Date.))

(. (Beans.) isDesignTime)

;; 6.4、构造java数据结构

(byte-array 40)

(double-array 10)

(def a  (into-array String ["this" "is" "a" "char" "queue"]))
                                                           
(aset a 0 "that")

a

(aget a 0)

(amap a idx ret (aset ret idx (clojure.string/upper-case (aget a idx))))

a

;; 6.5、doto和类型提示
(doto (Calendar/getInstance)
  (.set Calendar/YEAR 1990)
  (.set Calendar/MONTH 1)
  (.set Calendar/DAY_OF_MONTH 1))

(doto (Calendar/getInstance)
  (.set Calendar/YEAR 1900)
  (.set Calendar/MONTH 1)
  (.set Calendar/DAY_OF_MONTH 1))

;; 默认使用反射去找到参数的类型
(defn len [s]
  (.length s))

;; 直接向解释器传递参数类型
(defn len' [^String s]
  (.length s))

(time (reduce + map len (repeat  1000 "dsadadada")))
(time (reduce + map len' (repeat  1000 "dsadadada"))

;; 6.6、类的继承和接口实现
(import java.lang.Thread)

;; 继承Thread类 class MyThread extends Thread
(def mythread (proxy [Thread] [] (run [] (println "hello from proxy thread"))))

;; myThread.run
(.run mythread)

;;通过线程池执行自定义线程
(import java.util.concurrent.Executors)

(def pool (Executors/newFixedThreadPool 4))

(.submit pool mythread)

;; 实现接口
(def rt (proxy [Runnable] [] (run [] (println "hello from runnable thread"))))

(.submit pool rt)

;; reify实现多接口
(def thread2 (reify
               Comparable
               (compareTo [this other] -1)
               Runnable
               (run [this] (println "hello from reify Thread..."))))

(.submit pool thread2)

(.compareTo thread2 "")


;; 6.7、gen-class和aot

;; 通过gen-class动态生成java类
(gen-class
 :name testproj.MyClass
 :methods [[getName [] String]]
 :prefix "my-"
 :state state
 :init 
 :constructors {[String] []});; 指定构造方法

(defn my-getName [this]
  (:name (.state this)))

(defn my-init [name]
  [[] {:name name}])
  

;; 6.8、混合开发

(import MyClass)

(def my (MyClass. "sdadasdas"))

;; 调用对象的方法
(.getName my)

(import MyStaticsClass)

;; 调用静态方法
(MyStaticsClass/test)

(MyStaticsClass/testWithArg "ken")

(MyStaticsClass/testWithArgs "ken" "ben")



;; 7、并发基础

;; clojure所有函数都继承Runnable接口
(instance? Runnable (fn []))

(.start (Thread. (fn [] (println "hello from another thread"))))

;; clojure异步返回promise，通过deref或@ 获取异步执行结果
@(deliver (promise) "hi")


(defn long-run []
  (let [p (promise)]
    (.start (Thread. (fn []
                       (Thread/sleep 5000)
                       (deliver p "hello!"))))
    p))

;; 直接调用long-run返回一个promise
(long-run)

;; long=run调用
;; 第一种方式 deref
(deref (long-run))

;; 第二种方式 @
@(long-run)

;; promise使用
(let [p (long-run)]
  (println "waiting")
  @p)

;; promise变种 future(同步阻塞)
(defn long-fn2 []
  (Thread/sleep 5000)
  "hello from future")

@(future (long-fn2))

;; future异步阻塞使用
(defn log [content]
  (Thread/sleep 5000)
  (println "this is log：..." content))

(defn f []
  (future (log "this is balabala......"))
  :ok)

(f)

@(delay (f))


(defn fib [n]
  (if (< n 2 ) 1
       (+ (fib (- n 1))
     (fib (- n 2)))))

(time (fib 30))

(def fib' (memoize fib))

(time (fib' 30))

;; 8、core.async框架

;; demo 参见 myasync.clj

;; 9、STM
;; demo 参见 stm.clj

;; 10、类型定义

;; 类型定义 deftype
;; Clas Hello带一个参数name的构造函数
(deftype Hello [name])

;;get Hello的name属性
(.name (->Hello "Tom"))

;; 底层是一个map 
(defrecord Persion [name])

;; 使用map获取
(.name (->Persion "Lily"))

;; 构建map，再通过map获取
(:name (map->Persion {:name "susam"}))


;; 通过deftype 定义一个runnable类型
(deftype t2 [name]
  Runnable
  (run [this] (println (.name this))))

(.run (t2. "tom cat"))
